# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: server\routers\api\routes\__init__.py
import inspect, logging
from collections import defaultdict
from swagger import extract_routes
from server.routers.api.validator import validate_value

logger = logging.getLogger("server.routers.api.routes")


class Routes:
    """
    Interface class for working with API described in swagger documents.
    There are 2 important parameters:
        - base_path: for first hand route matching
        - _routes: a dict route_path:route_data where route_data is the regex for route matching and validation data
    """

    def __init__(self, swagger_document=None, base_path=None):
        self.routes = defaultdict(dict)
        self.base_path = base_path
        if swagger_document:
            self.base_path, self.routes = extract_routes(swagger_document)

    def add_route(
        self,
        method,
        path,
        handler_class,
        handler_method,
        regex,
        request,
        security=None,
        response=None,
    ):
        """
        Allows _routes manually to be created manually
        :param method:
        :param path:
        :param handler_class:
        :param handler_method:
        :param regex:
        :param request:
        :param security:
        :param response:
        :return:
        """
        self.routes[method][path] = dict(
            handler_class=handler_class,
            handler_method=handler_method,
            regex=regex,
            request=request,
            response=response,
            security=security,
        )

    def validate_parameter(
        self,
        method,
        path,
        name,
        value,
        collected_errors,
        ignore_required=False,
        add_defaults=True,
        accept_null_objects=False,
    ):
        """
        Validates request parameter value and collects errors in collected_errors
        :param accept_null_objects:
        :param method:
        :param path:
        :param name:
        :param value:
        :param collected_errors: dict
        :param ignore_required: bool
        :param add_defaults: bool
        :return:
        """
        descriptor = self.routes[method][path]["request"][name]
        validation_problems, value = validate_value(
            value,
            descriptor,
            path_param=name,
            ignore_required=ignore_required,
            add_defaults=add_defaults,
            accept_null_objects=accept_null_objects,
        )
        if validation_problems:
            collected_errors[name] = dict(
                src=descriptor["in"], problems=validation_problems
            )
        return value

    def check_routes(self, handler_classes):
        """
        This is a helper method for checking that there is a handler class for each api call with correct parameters
        :param handler_classes:
        :return:
        """
        logger.info("checking _routes:")
        handler_classes_not_implemented = set()
        handler_classes_with_problems = defaultdict(list)
        for method in self.routes:
            for route_path, route_info in self.routes[method].items():
                try:
                    handler_class = handler_classes[route_info["handler_class"]]
                except KeyError:
                    handler_classes_not_implemented.add(route_info["handler_class"])
                    continue

                handler_method = getattr(
                    handler_class, route_info["handler_method"], None
                )
                if handler_method is None:
                    handler_classes_with_problems[route_info["handler_class"]].append(
                        dict(
                            error="notimplemented", method=route_info["handler_method"]
                        )
                    )
                else:
                    args = inspect.getargspec(handler_method)
                    if len(args.args) == 0:
                        handler_classes_with_problems[
                            route_info["handler_class"]
                        ].append(
                            dict(error="no-args", method=route_info["handler_method"])
                        )
                    elif "self" != args.args[0]:
                        handler_classes_with_problems[
                            route_info["handler_class"]
                        ].append(
                            dict(
                                error="missing-self",
                                method=route_info["handler_method"],
                            )
                        )
                    elif not args.keywords:
                        handler_classes_with_problems[
                            route_info["handler_class"]
                        ].append(
                            dict(
                                error="missing-kwargs",
                                method=route_info["handler_method"],
                            )
                        )
                    else:
                        arguments = args.args[1:]
                        missing = []
                        extra = []
                        for arg_name in arguments:
                            if arg_name not in route_info["request"]:
                                extra.append(arg_name)

                        for arg_name in route_info["request"]:
                            if arg_name not in arguments:
                                missing.append(arg_name)

                        if missing or extra:
                            handler_classes_with_problems[
                                route_info["handler_class"]
                            ].append(
                                dict(
                                    error="param-mismatch",
                                    method=route_info["handler_method"],
                                    extra=extra,
                                    missing=missing,
                                )
                            )
                        else:
                            if args.defaults:
                                arguments_without_default = args.args[
                                    1 : -len(args.defaults)
                                ]
                            else:
                                arguments_without_default = args.args[1:]
                            if arguments_without_default:
                                missing_defaults = []
                                for arg_name in arguments_without_default:
                                    d = route_info["request"][arg_name]
                                    if not d["required"]:
                                        if "default" not in d:
                                            missing_defaults.append(arg_name)

                                if missing_defaults:
                                    handler_classes_with_problems[
                                        route_info["handler_class"]
                                    ].append(
                                        dict(
                                            error="missing-default",
                                            method=route_info["handler_method"],
                                            params=missing_defaults,
                                        )
                                    )

        return dict(
            missing_classes=handler_classes_not_implemented,
            missing_methods=handler_classes_with_problems,
        )
